From acc534ebfa2a3c292aca590c8a116a6340d2274d Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Wed, 23 Dec 2015 04:09:30 +0100 Subject: [PATCH] boxgadget: Add Adds a GtkBoxGadget that is a Gadget that behaves like a GtkBox. Use this gadget to implement the notebook base gadget. --- gtk/Makefile.am | 2 + gtk/gtkboxgadget.c | 511 ++++++++++++++++++++++++++++++++++++++ gtk/gtkboxgadgetprivate.h | 74 ++++++ gtk/gtknotebook.c | 334 ++++++------------------- 4 files changed, 658 insertions(+), 263 deletions(-) create mode 100644 gtk/gtkboxgadget.c create mode 100644 gtk/gtkboxgadgetprivate.h diff --git a/gtk/Makefile.am b/gtk/Makefile.am index ff259d18e7..527037a4bf 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -365,6 +365,7 @@ gtk_private_h_sources = \ gtkbitmaskprivateimpl.h \ gtkbookmarksmanager.h \ gtkboxprivate.h \ + gtkboxgadgetprivate.h \ gtkbuilderprivate.h \ gtkbuiltiniconprivate.h \ gtkbuttonprivate.h \ @@ -600,6 +601,7 @@ gtk_base_c_sources = \ gtkbookmarksmanager.c \ gtkborder.c \ gtkbox.c \ + gtkboxgadget.c \ gtkbuildable.c \ gtkbuilder.c \ gtkbuilderparser.c \ diff --git a/gtk/gtkboxgadget.c b/gtk/gtkboxgadget.c new file mode 100644 index 0000000000..6ea85296d6 --- /dev/null +++ b/gtk/gtkboxgadget.c @@ -0,0 +1,511 @@ +/* + * Copyright © 2015 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Authors: Benjamin Otte + */ + +#include "config.h" + +#include "gtkboxgadgetprivate.h" + +#include "gtkcssnodeprivate.h" +#include "gtkmain.h" +#include "gtkprivate.h" +#include "gtksizerequest.h" +#include "gtkwidgetprivate.h" + +typedef struct _GtkBoxGadgetPrivate GtkBoxGadgetPrivate; +struct _GtkBoxGadgetPrivate { + GtkOrientation orientation; + GArray *children; +}; + +typedef gboolean (* ComputeExpandFunc) (GObject *object, GtkOrientation orientation); + +typedef struct _GtkBoxGadgetChild GtkBoxGadgetChild; +struct _GtkBoxGadgetChild { + GObject *object; + ComputeExpandFunc compute_expand; +}; + +G_DEFINE_TYPE_WITH_CODE (GtkBoxGadget, gtk_box_gadget, GTK_TYPE_CSS_GADGET, + G_ADD_PRIVATE (GtkBoxGadget)) + +static gboolean +gtk_box_gadget_child_is_visible (GObject *child) +{ + if (GTK_IS_WIDGET (child)) + return gtk_widget_get_visible (GTK_WIDGET (child)); + else + return gtk_css_gadget_get_visible (GTK_CSS_GADGET (child)); +} + +static void +gtk_box_gadget_measure_child (GObject *child, + GtkOrientation orientation, + gint for_size, + gint *minimum, + gint *natural, + gint *minimum_baseline, + gint *natural_baseline) +{ + if (GTK_IS_WIDGET (child)) + { + _gtk_widget_get_preferred_size_for_size (GTK_WIDGET (child), + orientation, + for_size, + minimum, natural, + minimum_baseline, natural_baseline); + } + else + { + gtk_css_gadget_get_preferred_size (GTK_CSS_GADGET (child), + orientation, + for_size, + minimum, natural, + minimum_baseline, natural_baseline); + } +} + +static void +gtk_box_gadget_distribute (GtkBoxGadget *gadget, + gint size, + GtkRequestedSize *sizes) +{ + GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget)); + guint i, n_expand; + + n_expand = 0; + + for (i = 0 ; i < priv->children->len; i++) + { + GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i); + + gtk_box_gadget_measure_child (child->object, + priv->orientation, + -1, + &sizes[i].minimum_size, &sizes[i].natural_size, + NULL, NULL); + if (gtk_box_gadget_child_is_visible (child->object) && + child->compute_expand (child->object, priv->orientation)) + n_expand++; + size -= sizes[i].minimum_size; + } + + g_assert (size >= 0); + + size = gtk_distribute_natural_allocation (size, priv->children->len, sizes); + + if (size <= 0 || n_expand == 0) + return; + + for (i = 0 ; i < priv->children->len; i++) + { + GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i); + + if (!gtk_box_gadget_child_is_visible (child->object) || + !child->compute_expand (child->object, priv->orientation)) + continue; + + sizes[i].minimum_size += size / n_expand; + /* distribute all pixels, even if there's a remainder */ + size -= size / n_expand; + n_expand--; + } +} + +static void +gtk_box_gadget_measure_orientation (GtkCssGadget *gadget, + GtkOrientation orientation, + gint for_size, + gint *minimum, + gint *natural, + gint *minimum_baseline, + gint *natural_baseline) +{ + GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget)); + gint child_min, child_nat; + guint i; + + *minimum = 0; + *natural = 0; + + for (i = 0 ; i < priv->children->len; i++) + { + GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i); + + gtk_box_gadget_measure_child (child->object, + orientation, + for_size, + &child_min, &child_nat, + NULL, NULL); + + *minimum += child_min; + *natural += child_nat; + } +} + +static void +gtk_box_gadget_measure_opposite (GtkCssGadget *gadget, + GtkOrientation orientation, + gint for_size, + gint *minimum, + gint *natural, + gint *minimum_baseline, + gint *natural_baseline) +{ + GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget)); + int child_min, child_nat, child_min_baseline, child_nat_baseline; + int total_min, above_min, below_min, total_nat, above_nat, below_nat; + GtkRequestedSize *sizes; + guint i; + + if (for_size >= 0) + { + sizes = g_newa (GtkRequestedSize, priv->children->len); + gtk_box_gadget_distribute (GTK_BOX_GADGET (gadget), for_size, sizes); + } + + above_min = below_min = above_nat = below_nat = -1; + total_min = total_nat = 0; + + for (i = 0 ; i < priv->children->len; i++) + { + GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i); + + gtk_box_gadget_measure_child (child->object, + orientation, + for_size >= 0 ? sizes[i].minimum_size : for_size, + &child_min, &child_nat, + &child_min_baseline, &child_nat_baseline); + + if (child_min_baseline >= 0) + { + above_min = MAX (above_min, child_min - child_min_baseline); + below_min = MAX (below_min, child_min_baseline); + above_nat = MAX (above_nat, child_nat - child_nat_baseline); + below_nat = MAX (below_nat, child_nat_baseline); + } + else + { + total_min = MAX (total_min, child_min); + total_nat = MAX (total_nat, child_nat); + } + } + + if (above_min >= 0) + { + total_min = MAX (total_min, above_min + below_min); + total_nat = MAX (total_nat, above_nat + below_nat); + /* assume GTK_BASELINE_POSITION_CENTER for now */ + *minimum_baseline = above_min + (total_min - (above_min + below_min)) / 2; + *natural_baseline = above_nat + (total_nat - (above_nat + below_nat)) / 2; + } + + *minimum = total_min; + *natural = total_nat; +} + +static void +gtk_box_gadget_get_preferred_size (GtkCssGadget *gadget, + GtkOrientation orientation, + gint for_size, + gint *minimum, + gint *natural, + gint *minimum_baseline, + gint *natural_baseline) +{ + GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget)); + + if (priv->orientation == orientation) + gtk_box_gadget_measure_orientation (gadget, orientation, for_size, minimum, natural, minimum_baseline, natural_baseline); + else + gtk_box_gadget_measure_opposite (gadget, orientation, for_size, minimum, natural, minimum_baseline, natural_baseline); +} + +static void +gtk_box_gadget_allocate_child (GObject *child, + GtkAllocation *allocation, + int baseline, + GtkAllocation *out_clip) +{ + if (GTK_IS_WIDGET (child)) + { + gtk_widget_size_allocate_with_baseline (GTK_WIDGET (child), + allocation, + baseline); + gtk_widget_get_clip (GTK_WIDGET (child), out_clip); + } + else + { + gtk_css_gadget_allocate (GTK_CSS_GADGET (child), + allocation, + baseline, + out_clip); + } +} + +static void +gtk_box_gadget_allocate (GtkCssGadget *gadget, + const GtkAllocation *allocation, + int baseline, + GtkAllocation *out_clip) +{ + GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget)); + GtkRequestedSize *sizes; + GtkAllocation child_allocation, child_clip; + guint i; + + child_allocation = *allocation; + sizes = g_newa (GtkRequestedSize, priv->children->len); + + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + gtk_box_gadget_distribute (GTK_BOX_GADGET (gadget), allocation->width, sizes); + for (i = 0 ; i < priv->children->len; i++) + { + GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i); + + child_allocation.width = sizes[i].minimum_size; + gtk_box_gadget_allocate_child (child->object, &child_allocation, baseline, &child_clip); + if (i == 0) + *out_clip = child_clip; + else + gdk_rectangle_union (out_clip, &child_clip, out_clip); + child_allocation.x += sizes[i].minimum_size; + } + } + else + { + gtk_box_gadget_distribute (GTK_BOX_GADGET (gadget), allocation->height, sizes); + for (i = 0 ; i < priv->children->len; i++) + { + GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i); + + child_allocation.height = sizes[i].minimum_size; + gtk_box_gadget_allocate_child (child->object, &child_allocation, -1, &child_clip); + if (i == 0) + *out_clip = child_clip; + else + gdk_rectangle_union (out_clip, &child_clip, out_clip); + child_allocation.y += sizes[i].minimum_size; + } + } +} + +static gboolean +gtk_box_gadget_draw (GtkCssGadget *gadget, + cairo_t *cr, + int x, + int y, + int width, + int height) +{ + GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget)); + guint i; + + for (i = 0 ; i < priv->children->len; i++) + { + GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i); + + if (GTK_IS_WIDGET (child->object)) + { + gtk_container_propagate_draw (GTK_CONTAINER (gtk_css_gadget_get_owner (gadget)), + GTK_WIDGET (child->object), + cr); + } + else + { + gtk_css_gadget_draw (GTK_CSS_GADGET (child->object), + cr); + } + } + + return FALSE; +} + +static void +gtk_box_gadget_finalize (GObject *object) +{ + GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (object)); + + g_array_free (priv->children, TRUE); + + G_OBJECT_CLASS (gtk_box_gadget_parent_class)->finalize (object); +} + +static void +gtk_box_gadget_class_init (GtkBoxGadgetClass *klass) +{ + GtkCssGadgetClass *gadget_class = GTK_CSS_GADGET_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gtk_box_gadget_finalize; + + gadget_class->get_preferred_size = gtk_box_gadget_get_preferred_size; + gadget_class->allocate = gtk_box_gadget_allocate; + gadget_class->draw = gtk_box_gadget_draw; +} + +static void +gtk_box_gadget_clear_child (gpointer data) +{ + GtkBoxGadgetChild *child = data; + + g_object_unref (child->object); +} + +static void +gtk_box_gadget_init (GtkBoxGadget *gadget) +{ + GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (gadget); + + priv->children = g_array_new (FALSE, FALSE, sizeof (GtkBoxGadgetChild)); + g_array_set_clear_func (priv->children, gtk_box_gadget_clear_child); +} + +GtkCssGadget * +gtk_box_gadget_new_for_node (GtkCssNode *node, + GtkWidget *owner) +{ + return g_object_new (GTK_TYPE_BOX_GADGET, + "node", node, + "owner", owner, + NULL); +} + +GtkCssGadget * +gtk_box_gadget_new (const char *name, + GtkWidget *owner, + GtkCssGadget *parent, + GtkCssGadget *next_sibling) +{ + GtkCssNode *node; + GtkCssGadget *result; + + node = gtk_css_node_new (); + gtk_css_node_set_name (node, g_intern_string (name)); + if (parent) + gtk_css_node_insert_before (gtk_css_gadget_get_node (parent), + node, + next_sibling ? gtk_css_gadget_get_node (next_sibling) : NULL); + + result = gtk_box_gadget_new_for_node (node, owner); + + g_object_unref (node); + + return result; +} + +void +gtk_box_gadget_set_orientation (GtkBoxGadget *gadget, + GtkOrientation orientation) +{ + GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (gadget); + + priv->orientation = orientation; +} + +static void +gtk_box_gadget_insert_object (GtkBoxGadget *gadget, + int pos, + GObject *object, + ComputeExpandFunc compute_expand_func) +{ + GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (gadget); + GtkBoxGadgetChild child; + + child.object = g_object_ref (object); + child.compute_expand = compute_expand_func; + + if (pos < 0 || pos >= priv->children->len) + g_array_append_val (priv->children, child); + else + g_array_insert_val (priv->children, pos, child); +} + +void +gtk_box_gadget_insert_widget (GtkBoxGadget *gadget, + int pos, + GtkWidget *widget) +{ + gtk_box_gadget_insert_object (gadget, + pos, + G_OBJECT (widget), + (ComputeExpandFunc) gtk_widget_compute_expand); +} + +void +gtk_box_gadget_remove_object (GtkBoxGadget *gadget, + GObject *object) +{ + GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (gadget); + guint i; + + for (i = 0; i < priv->children->len; i++) + { + GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i); + + if (child->object == object) + { + g_array_remove_index (priv->children, i); + break; + } + } +} + +void +gtk_box_gadget_remove_widget (GtkBoxGadget *gadget, + GtkWidget *widget) +{ + gtk_box_gadget_remove_object (gadget, G_OBJECT (widget)); +} + +static gboolean +only_horizontal (GObject *object, + GtkOrientation orientation) +{ + return orientation == GTK_ORIENTATION_HORIZONTAL; +} + +static gboolean +only_vertical (GObject *object, + GtkOrientation orientation) +{ + return orientation == GTK_ORIENTATION_VERTICAL; +} + +void +gtk_box_gadget_insert_gadget (GtkBoxGadget *gadget, + int pos, + GtkCssGadget *cssgadget, + gboolean hexpand, + gboolean vexpand) +{ + gtk_box_gadget_insert_object (gadget, + pos, + G_OBJECT (cssgadget), + hexpand ? (vexpand ? (ComputeExpandFunc) gtk_true : only_horizontal) + : (vexpand ? only_vertical : (ComputeExpandFunc) gtk_false)); +} + +void +gtk_box_gadget_remove_gadget (GtkBoxGadget *gadget, + GtkCssGadget *cssgadget) +{ + gtk_box_gadget_remove_object (gadget, G_OBJECT (cssgadget)); +} + diff --git a/gtk/gtkboxgadgetprivate.h b/gtk/gtkboxgadgetprivate.h new file mode 100644 index 0000000000..ce64e4186a --- /dev/null +++ b/gtk/gtkboxgadgetprivate.h @@ -0,0 +1,74 @@ +/* + * Copyright © 2015 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Authors: Benjamin Otte + */ + +#ifndef __GTK_BOX_GADGET_PRIVATE_H__ +#define __GTK_BOX_GADGET_PRIVATE_H__ + +#include "gtk/gtkcssgadgetprivate.h" + +G_BEGIN_DECLS + +#define GTK_TYPE_BOX_GADGET (gtk_box_gadget_get_type ()) +#define GTK_BOX_GADGET(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_BOX_GADGET, GtkBoxGadget)) +#define GTK_BOX_GADGET_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_BOX_GADGET, GtkBoxGadgetClass)) +#define GTK_IS_BOX_GADGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_BOX_GADGET)) +#define GTK_IS_BOX_GADGET_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_BOX_GADGET)) +#define GTK_BOX_GADGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_BOX_GADGET, GtkBoxGadgetClass)) + +typedef struct _GtkBoxGadget GtkBoxGadget; +typedef struct _GtkBoxGadgetClass GtkBoxGadgetClass; + +struct _GtkBoxGadget +{ + GtkCssGadget parent; +}; + +struct _GtkBoxGadgetClass +{ + GtkCssGadgetClass parent_class; +}; + +GType gtk_box_gadget_get_type (void) G_GNUC_CONST; + +GtkCssGadget * gtk_box_gadget_new (const char *name, + GtkWidget *owner, + GtkCssGadget *parent, + GtkCssGadget *next_sibling); +GtkCssGadget * gtk_box_gadget_new_for_node (GtkCssNode *node, + GtkWidget *owner); + +void gtk_box_gadget_set_orientation (GtkBoxGadget *gadget, + GtkOrientation orientation); + +void gtk_box_gadget_insert_widget (GtkBoxGadget *gadget, + int pos, + GtkWidget *widget); +void gtk_box_gadget_remove_widget (GtkBoxGadget *gadget, + GtkWidget *widget); +void gtk_box_gadget_insert_gadget (GtkBoxGadget *gadget, + int pos, + GtkCssGadget *cssgadget, + gboolean hexpand, + gboolean vexpand); +void gtk_box_gadget_remove_gadget (GtkBoxGadget *gadget, + GtkCssGadget *cssgadget); + +G_END_DECLS + +#endif /* __GTK_BOX_GADGET_PRIVATE_H__ */ diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c index 38dab30fb1..727f2211ef 100644 --- a/gtk/gtknotebook.c +++ b/gtk/gtknotebook.c @@ -43,6 +43,7 @@ #include "gtkbuildable.h" #include "gtktypebuiltins.h" #include "gtkwidgetpath.h" +#include "gtkboxgadgetprivate.h" #include "gtkcsscustomgadgetprivate.h" #include "gtkcssstylepropertyprivate.h" #include "gtksizerequest.h" @@ -521,26 +522,6 @@ static gboolean gtk_notebook_draw_stack (GtkCssGadget *gadget, int width, int height, gpointer data); -static void gtk_notebook_measure_contents (GtkCssGadget *gadget, - GtkOrientation orientation, - gint for_size, - gint *minimum, - gint *natural, - gint *minimum_baseline, - gint *natural_baseline, - gpointer data); -static void gtk_notebook_allocate_contents (GtkCssGadget *gadget, - const GtkAllocation *allocation, - int baseline, - GtkAllocation *out_clip, - gpointer data); -static gboolean gtk_notebook_draw_contents (GtkCssGadget *gadget, - cairo_t *cr, - int x, - int y, - int width, - int height, - gpointer data); /*** GtkNotebook Private Functions ***/ static void gtk_notebook_redraw_tabs (GtkNotebook *notebook); @@ -603,6 +584,8 @@ static void gtk_notebook_menu_label_unparent (GtkWidget *widget, static void gtk_notebook_menu_detacher (GtkWidget *widget, GtkMenu *menu); +static void gtk_notebook_update_tab_pos (GtkNotebook *notebook); + /*** GtkNotebook Private Setters ***/ static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child, gboolean overload, @@ -1350,14 +1333,10 @@ gtk_notebook_init (GtkNotebook *notebook) gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE); widget_node = gtk_widget_get_css_node (GTK_WIDGET (notebook)); - priv->gadget = gtk_css_custom_gadget_new_for_node (widget_node, - GTK_WIDGET (notebook), - gtk_notebook_measure_contents, - gtk_notebook_allocate_contents, - gtk_notebook_draw_contents, - NULL, - NULL); + priv->gadget = gtk_box_gadget_new_for_node (widget_node, + GTK_WIDGET (notebook)); gtk_css_gadget_add_class (priv->gadget, GTK_STYLE_CLASS_FRAME); + gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->gadget), GTK_ORIENTATION_VERTICAL); priv->stack_gadget = gtk_css_custom_gadget_new ("stack", GTK_WIDGET (notebook), @@ -1369,6 +1348,7 @@ gtk_notebook_init (GtkNotebook *notebook) NULL, NULL); gtk_css_gadget_set_state (priv->stack_gadget, gtk_css_node_get_state (widget_node)); + gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), -1, priv->stack_gadget, TRUE, TRUE); priv->header_gadget = gtk_css_custom_gadget_new ("header", GTK_WIDGET (notebook), @@ -1381,6 +1361,8 @@ gtk_notebook_init (GtkNotebook *notebook) NULL); gtk_css_gadget_add_class (priv->header_gadget, GTK_STYLE_CLASS_TOP); gtk_css_gadget_set_state (priv->header_gadget, gtk_css_node_get_state (widget_node)); + gtk_css_gadget_set_visible (priv->header_gadget, FALSE); + gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 0, priv->header_gadget, FALSE, FALSE); priv->tabs_node = gtk_css_node_new (); gtk_css_node_set_name (priv->tabs_node, I_("tabs")); @@ -1995,7 +1977,7 @@ gtk_notebook_realize (GtkWidget *widget) gtk_widget_set_realized (widget, TRUE); - gtk_notebook_get_event_window_position (notebook, &event_window_pos); + gtk_css_gadget_get_border_allocation (priv->header_gadget, &event_window_pos, NULL); window = gtk_widget_get_parent_window (widget); gtk_widget_set_window (widget, window); @@ -2280,115 +2262,6 @@ gtk_notebook_measure_stack (GtkCssGadget *gadget, } } -static GtkOrientation -get_orientation_from_tab_pos (GtkNotebook *notebook) -{ - GtkPositionType tab_pos = notebook->priv->tab_pos; - - if (tab_pos == GTK_POS_LEFT || tab_pos == GTK_POS_RIGHT) - return GTK_ORIENTATION_HORIZONTAL; - else - return GTK_ORIENTATION_VERTICAL; -} - -static void -gtk_notebook_distribute_content_size (GtkNotebook *notebook, - gint size, - gint *header_size, - gint *stack_size) -{ - GtkNotebookPrivate *priv = notebook->priv; - GtkOrientation orientation = get_orientation_from_tab_pos (notebook); - GtkRequestedSize request[2]; - - if (size < 0) - { - *header_size = -1; - *stack_size = -1; - return; - } - - gtk_css_gadget_get_preferred_size (priv->header_gadget, - orientation, - -1, - &request[0].minimum_size, &request[0].natural_size, - NULL, NULL); - gtk_css_gadget_get_preferred_size (priv->stack_gadget, - orientation, - -1, - &request[1].minimum_size, &request[1].natural_size, - NULL, NULL); - - size = gtk_distribute_natural_allocation (size - request[0].minimum_size - request[1].minimum_size, - G_N_ELEMENTS (request), - request); - - *header_size = request[0].minimum_size; - *stack_size = request[1].minimum_size + size; -} - -static void -gtk_notebook_measure_contents (GtkCssGadget *gadget, - GtkOrientation orientation, - gint size, - gint *minimum, - gint *natural, - gint *minimum_baseline, - gint *natural_baseline, - gpointer unused) -{ - GtkWidget *widget = gtk_css_gadget_get_owner (gadget); - GtkNotebook *notebook = GTK_NOTEBOOK (widget); - GtkNotebookPrivate *priv = notebook->priv; - gint stack_min, stack_nat, header_min, header_nat; - - if (!priv->show_tabs || !gtk_notebook_has_current_page (notebook)) - { - gtk_css_gadget_get_preferred_size (priv->stack_gadget, - orientation, - size, - minimum, natural, - NULL, NULL); - - } - else if (orientation == get_orientation_from_tab_pos (notebook)) - { - gtk_css_gadget_get_preferred_size (priv->header_gadget, - orientation, - size, - &header_min, &header_nat, - NULL, NULL); - gtk_css_gadget_get_preferred_size (priv->stack_gadget, - orientation, - size, - &stack_min, &stack_nat, - NULL, NULL); - - *minimum = header_min + stack_min; - *natural = header_nat + stack_nat; - } - else - { - gint header_size, stack_size; - - gtk_notebook_distribute_content_size (notebook, size, &header_size, &stack_size); - - gtk_css_gadget_get_preferred_size (priv->header_gadget, - orientation, - header_size, - &header_min, &header_nat, - NULL, NULL); - gtk_css_gadget_get_preferred_size (priv->stack_gadget, - orientation, - stack_size, - &stack_min, &stack_nat, - NULL, NULL); - - *minimum = MAX (header_min, stack_min); - *natural = MAX (header_nat, stack_nat); - } -} - static void gtk_notebook_get_preferred_width_for_height (GtkWidget *widget, gint height, @@ -2518,106 +2391,39 @@ gtk_notebook_allocate_stack (GtkCssGadget *gadget, } static void -gtk_notebook_allocate_contents (GtkCssGadget *gadget, - const GtkAllocation *allocation, - int baseline, - GtkAllocation *out_clip, - gpointer unused) +gtk_notebook_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) { - GtkWidget *widget = gtk_css_gadget_get_owner (gadget); GtkNotebook *notebook = GTK_NOTEBOOK (widget); GtkNotebookPrivate *priv = notebook->priv; - GtkAllocation stack_allocation, header_allocation; - - stack_allocation = *allocation; - - if (!priv->show_tabs || !gtk_notebook_has_current_page (notebook)) - { - gtk_css_gadget_allocate (priv->stack_gadget, &stack_allocation, -1, out_clip); - if (gtk_widget_get_realized (widget)) - gdk_window_hide (priv->event_window); - } - else - { - GtkAllocation stack_clip, header_clip; - - header_allocation = stack_allocation; - - switch (get_effective_tab_pos (notebook)) - { - case GTK_POS_TOP: - gtk_notebook_distribute_content_size (notebook, - stack_allocation.height, - &header_allocation.height, - &stack_allocation.height); - stack_allocation.y += header_allocation.height; - break; - - case GTK_POS_BOTTOM: - gtk_notebook_distribute_content_size (notebook, - stack_allocation.height, - &header_allocation.height, - &stack_allocation.height); - header_allocation.y += stack_allocation.height; - break; - - case GTK_POS_LEFT: - gtk_notebook_distribute_content_size (notebook, - stack_allocation.width, - &header_allocation.width, - &stack_allocation.width); - stack_allocation.x += header_allocation.width; - break; + GtkAllocation clip; - case GTK_POS_RIGHT: - gtk_notebook_distribute_content_size (notebook, - stack_allocation.width, - &header_allocation.width, - &stack_allocation.width); - header_allocation.x += stack_allocation.width; - break; + gtk_widget_set_allocation (widget, allocation); - default: - g_assert_not_reached (); - break; - } + gtk_css_gadget_allocate (priv->gadget, + allocation, + gtk_widget_get_allocated_baseline (widget), + &clip); - gtk_css_gadget_allocate (priv->header_gadget, &header_allocation, -1, &header_clip); - gtk_css_gadget_allocate (priv->stack_gadget, &stack_allocation, -1, &stack_clip); + gtk_widget_set_clip (widget, &clip); - gdk_rectangle_union (&stack_clip, &header_clip, out_clip); + if (gtk_widget_get_realized (widget)) + { + GdkRectangle position; - if (gtk_widget_get_realized (widget)) + if (gtk_notebook_get_event_window_position (notebook, &position)) { - GtkAllocation position; - gtk_css_gadget_get_border_allocation (priv->header_gadget, &position, NULL); gdk_window_move_resize (priv->event_window, position.x, position.y, position.width, position.height); if (gtk_widget_get_mapped (GTK_WIDGET (notebook))) gdk_window_show_unraised (priv->event_window); } + else + gdk_window_hide (priv->event_window); } } -static void -gtk_notebook_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) -{ - GtkNotebook *notebook = GTK_NOTEBOOK (widget); - GtkNotebookPrivate *priv = notebook->priv; - GtkAllocation clip; - - gtk_widget_set_allocation (widget, allocation); - - gtk_css_gadget_allocate (priv->gadget, - allocation, - gtk_widget_get_allocated_baseline (widget), - &clip); - - gtk_widget_set_clip (widget, &clip); -} - static gboolean gtk_notebook_draw_stack (GtkCssGadget *gadget, cairo_t *cr, @@ -2639,40 +2445,6 @@ gtk_notebook_draw_stack (GtkCssGadget *gadget, return FALSE; } -static gboolean -gtk_notebook_draw_contents (GtkCssGadget *gadget, - cairo_t *cr, - int x, - int y, - int width, - int height, - gpointer unused) -{ - GtkWidget *widget = gtk_css_gadget_get_owner (gadget); - GtkNotebook *notebook = GTK_NOTEBOOK (widget); - GtkNotebookPrivate *priv = notebook->priv; - GdkWindow *window; - - window = gtk_widget_get_window (widget); - if (gtk_cairo_should_draw_window (cr, window)) - { - gtk_css_gadget_draw (priv->stack_gadget, cr); - - if (priv->show_tabs && gtk_notebook_has_current_page (notebook)) - gtk_css_gadget_draw (priv->header_gadget, cr); - } - - if (gtk_notebook_has_current_page (notebook) && priv->operation == DRAG_OPERATION_REORDER && - gtk_cairo_should_draw_window (cr, priv->drag_window)) - { - gtk_notebook_draw_tab (notebook, - priv->cur_page, - cr); - } - - return FALSE; -} - static gboolean gtk_notebook_draw (GtkWidget *widget, cairo_t *cr) @@ -4800,19 +4572,22 @@ page_visible_cb (GtkWidget *child, gtk_widget_set_visible (parent, gtk_widget_get_visible (child)); } - if (priv->cur_page == page && - !gtk_widget_get_visible (child)) + if (priv->cur_page == page) { - list = g_list_find (priv->children, priv->cur_page); - if (list) + if (!gtk_widget_get_visible (child)) { - next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE); - if (!next) - next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE); - } + list = g_list_find (priv->children, priv->cur_page); + if (list) + { + next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE); + if (!next) + next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE); + } - if (next) - gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next)); + if (next) + gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next)); + } + gtk_css_gadget_set_visible (priv->header_gadget, priv->show_tabs && gtk_notebook_has_current_page (notebook)); } if (!gtk_notebook_has_current_page (notebook) && gtk_widget_get_visible (child)) @@ -6632,6 +6407,7 @@ gtk_notebook_real_switch_page (GtkNotebook *notebook, priv->cur_page = page; gtk_css_node_set_state (page->cssnode, gtk_css_node_get_state (page->cssnode) | GTK_STATE_FLAG_ACTIVE); + gtk_css_gadget_set_visible (priv->header_gadget, priv->show_tabs); if (!priv->focus_tab || priv->focus_tab->data != (gpointer) priv->cur_page) @@ -7418,11 +7194,14 @@ gtk_notebook_set_show_tabs (GtkNotebook *notebook, else gtk_widget_hide (page->tab_label); } + gtk_css_gadget_set_visible (priv->header_gadget, + gtk_notebook_has_current_page (notebook)); } else { gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE); gtk_notebook_update_labels (notebook); + gtk_css_gadget_set_visible (priv->header_gadget, FALSE); } for (i = 0; i < N_ACTION_WIDGETS; i++) @@ -7431,6 +7210,7 @@ gtk_notebook_set_show_tabs (GtkNotebook *notebook, gtk_widget_set_child_visible (priv->action_widget[i], show_tabs); } + gtk_notebook_update_tab_pos (notebook); gtk_widget_reset_style (GTK_WIDGET (notebook)); gtk_widget_queue_resize (GTK_WIDGET (notebook)); @@ -7476,6 +7256,34 @@ gtk_notebook_update_tab_pos (GtkNotebook *notebook) else gtk_css_gadget_remove_class (priv->header_gadget, tab_pos_names[i]); } + + gtk_box_gadget_remove_gadget (GTK_BOX_GADGET (priv->gadget), priv->header_gadget); + switch (tab_pos) + { + case GTK_POS_TOP: + if (priv->show_tabs) + gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 0, priv->header_gadget, FALSE, FALSE); + gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->gadget), GTK_ORIENTATION_VERTICAL); + break; + + case GTK_POS_BOTTOM: + if (priv->show_tabs) + gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 1, priv->header_gadget, FALSE, FALSE); + gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->gadget), GTK_ORIENTATION_VERTICAL); + break; + + case GTK_POS_LEFT: + if (priv->show_tabs) + gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 0, priv->header_gadget, FALSE, FALSE); + gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->gadget), GTK_ORIENTATION_HORIZONTAL); + break; + + case GTK_POS_RIGHT: + if (priv->show_tabs) + gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 1, priv->header_gadget, FALSE, FALSE); + gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->gadget), GTK_ORIENTATION_HORIZONTAL); + break; + } } /** -- 2.30.2